package middleware

import (
	"fmt"
	"github.com/gin-gonic/gin"
	retalog "github.com/lestrrat-go/file-rotatelogs" //分割日志
	"github.com/rifflock/lfshook"                    //分割日志
	"github.com/sirupsen/logrus"                     //日志管理
	"math"
	"os"
	"time"
)

func Logger() gin.HandlerFunc {
	filePath := "log/log"
	//todo:最新的log以管理员权限运行就不会报错这里略过
	//linkName := "latest_log.log" //最新的log
	scr, err := os.OpenFile(filePath, os.O_RDWR|os.O_CREATE, 0755)
	if err != nil {
		fmt.Println("err:", err)
	}
	//0644：所有者可读、写；组和其他人可读。
	//0700：所有者可读、写、执行；组和其他人无权限
	//0755：所有者具有读、写和执行权限，而组用户和其他用户具有读和执行权限
	logger := logrus.New() //把logrus实例出来
	logger.Out = scr

	logger.SetLevel(logrus.DebugLevel)
	logWriter, _ := retalog.New(
		filePath+"%Y%m%d.log",                  //设置年月日
		retalog.WithMaxAge(7*24*time.Hour),     //最大存储时间
		retalog.WithRotationTime(24*time.Hour), // 24小时分割一次
		//retalog.WithLinkName(linkName),
	)
	WriteMap := lfshook.WriterMap{ //文件相关信息写入logWriter
		logrus.InfoLevel:  logWriter,
		logrus.FatalLevel: logWriter,
		logrus.DebugLevel: logWriter,
		logrus.WarnLevel:  logWriter,
		logrus.ErrorLevel: logWriter,
		logrus.PanicLevel: logWriter,
	}

	Hook := lfshook.NewHook(WriteMap, &logrus.TextFormatter{
		TimestampFormat: "2006-01-02 15:04:05", // 时间格式固定的time包格式
		FullTimestamp:   true,                  // 显示完整时间
	})
	logger.AddHook(Hook)
	return func(c *gin.Context) {
		startTime := time.Now()
		c.Next()                                                                                     //中间件是洋葱模型
		stopTime := time.Since(startTime)                                                            //传入startTime证明是一个时间段
		spendTime := fmt.Sprintf("%d ms", int(math.Ceil(float64(stopTime.Nanoseconds())/1000000.0))) //花费时间精确到纳秒
		hostName, err := os.Hostname()
		if err != nil {
			hostName = "unknown"
		}
		statusCode := c.Writer.Status()    //状态码
		clientIp := c.ClientIP()           //客户端IP
		userAgent := c.Request.UserAgent() //客户端请求信息（如谷歌浏览器或是版本这些）
		dataSize := c.Writer.Size()        //请求长度
		if dataSize < 0 {
			dataSize = 0
		}
		method := c.Request.Method   //请求方法
		path := c.Request.RequestURI //请求路径

		entry := logger.WithFields(logrus.Fields{
			"HostName":  hostName,
			"Status":    statusCode,
			"SpendTime": spendTime,
			"IP":        clientIp,
			"Method":    method,
			"Path":      path,
			"DataSize":  dataSize,
			"Agent":     userAgent,
		})
		if len(c.Errors) > 0 {
			entry.Error(c.Errors.ByType(gin.ErrorTypePrivate).String()) //如果有错误，就记录到logrus
		}
		if statusCode >= 500 {
			entry.Error()
		} else if statusCode >= 400 {
			entry.Warn()
		} else {
			entry.Info()
		}
	}
}
